<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script>
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
        #state = PENDING
        #value = undefined
        #handler = []
        constructor (executer) {
            const resolve = (data) => {
                this.#stateChange(FULFILLED, data)
            }
            const reject = (reason) => {
                this.#stateChange(REJECTED, reason)
            }
            try {
                executer(resolve, reject)
            } catch (error) {
                reject(error)
            }
        }
        #stateChange(state, value) {
            if (this.#state !== PENDING) return
            this.#state = state
            this.#value = value
            this.#run()
        }
        #isPromiseLike(value) {
            if (typeof value !== null && (typeof value === 'object' || typeof value === 'function')) {
                return typeof value.then === 'function'
            }
            return false
        }
        #run() {
            if (this.#state !== PENDING) return
            while(this.#handler.length) {
                const { onFulfilled, onRejected, resolve, reject } = this.#handler.shift()
                if (this.#state === FULFILLED) {
                    this.#runOne(onFulfilled, resolve, reject)
                } else {
                    this.#runOne(onRejected, resolve, reject)
                }
            }
        }
        #runOne(callBack, resolve, reject) {
            if (typeof callBack !== 'function') {
                const settled = this.#state === FULFILLED ? resolve : reject
                    settled(this.#value)
                    return
            } else {
                if (this.#isPromiseLike(callBack)) {
                    callBack.then(resolve, reject)
                } else {
                    resolve(this.#value)
                }
            }
        }
        then (onFulfilled ,onRejected) {
            return new MyPromise((resolve, reject) => {
                this.#handler.push({
                    onFulfilled,
                    onRejected,
                    resolve,
                    reject
                })
                this.#run()
            })
        }
    }
    const p = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            reject(1)
        }, 1000)
    })
    p.then(res => {
        console.log('res', res)
    }, err => {
        console.log('err', err)
    }).finally(() => {
        console.log('执行')
    })
    </script>
<body>
    
</body>
</html>